#include <unordered_map>
#include <csignal>

#include "perf_component.h"
#include "data_house/datahouse.h"
#include "common/configs/config_gflags.h"
#include "latency_util/latency_record.h"
#include "apollo/logger/signal_handler.h"

int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
    size_t newlen) {
    (void) name;
    (void) oldp;
    (void) oldlenp;
    (void) newp;
    return 0;
}
extern "C" {

int32_t get_asan_status() {
    return -1;
}

int32_t get_asan_status1() {
    return -1;
}

}

namespace perfcom {

using apollo::common::DataHouse;

static int filter(const struct dirent *dir) {
    if (dir->d_name[0] == '.') {
        return 0;
    } else {
        return 1;
    }
}

PerfComponent::PerfComponent() {}

void PerfComponent::stoptop() {
    // kill top cmd
    std::string cmd =
        "ps aux|grep 'top -c -w 500 -d 1 -b' |grep -v grep | awk '{print $2}' | "
        "xargs -i kill -9 {}";
    system(cmd.c_str());

    // kill top h
    cmd =
        "ps aux|grep 'top -H -w 500 -d 1 -b' |grep -v grep | awk '{print $2}' | "
        "xargs -i kill -9 {}";
    system(cmd.c_str());

    // kill tegrastat cmd
    cmd =
        "ps aux|grep 'tegrastats --interval " + std::to_string(conf.igpu_interval()) +
        "' |grep -v grep | awk '{print $2}' | xargs -i kill -9 {}";
    system(cmd.c_str());

    // kill pidstat cmd
    cmd =
        "ps aux|grep 'pidstat -t 1 -d' |grep -v grep | awk '{print $2}' | "
        "xargs -i kill -9 {}";
    system(cmd.c_str());
}

void PerfComponent::stopiostat() {
    std::string cmd =
        "ps aux|grep 'iostat -t 1' |grep -v grep | awk '{print $2}' | "
        "xargs kill -9";
    system(cmd.c_str());
}

PerfComponent::~PerfComponent() {
    stoptop();
    stopiostat();
    killed = true;
    if (cpu_thread != nullptr && cpu_thread->joinable()) {
        cpu_thread->join();
    }
    if (fp_cpu != nullptr) {
        pclose(fp_cpu);
    }
    if (fp_cpu_thread != nullptr) {
        pclose(fp_cpu_thread);
    }
    if (fp_pidstat_ != nullptr) {
        pclose(fp_pidstat_);
    }
    if (io_thread != nullptr && io_thread->joinable()) {
        io_thread->join();
    }
    if (fp_io != nullptr) {
        pclose(fp_io);
    }
}

bool PerfComponent::Init() {
    return cybertron::SUCC;
}

bool PerfComponent::ProcInit() {
    int ret = GetProtoConfig(&conf);
    CHECK_FAIL_AND_RETURN_VALUE(ret, cybertron::FAIL);

    if (cpu_check_thread() != cybertron::SUCC) {
        return cybertron::FAIL;
    }

    if (conf.mutable_ioperf()->io_enable() && (io_check_thread() != cybertron::SUCC)) {
        return cybertron::FAIL;
    }
    char* flag = getenv("ENABLE_GPU_MEM_MONITOR");
    if (flag !=  nullptr && std::string(flag) == "1") {
        enable_gpu_mem_monitor_ = true;
    }
    flag = getenv("ENABLE_DUMP_ALL_BT");
    if (flag !=  nullptr && std::string(flag) == "1") {
        enable_dump_all_bt_ = true;
    }
    flag = getenv("HW_VERSION");
    if (flag !=  nullptr && std::string(flag) == "ORIN") {
        is_orinx_ = true;
    }
    apollo::common::util::LatencyRecord::Instance()->EnableLatencyRecord(FLAGS_enable_latency_record);
    apollo::common::util::LatencyRecord::Instance()->EnableMetatimeRecord(FLAGS_enable_metatime_record);
    apollo::common::util::LatencyRecord::Instance()->SetLatencyLevel(FLAGS_latency_record_level);

    node_.reset(new cybertron::Node("perfcom_" + conf.plate_type()));
    if (conf.plate_type() == "master") {
        scene_reader_ = node_->CreateReader<apollo::planning::ExecutorInfo>("/pnc/executor_info", nullptr);
        statemachine_reader_ =
            node_->CreateReader<apollo::status_machine::GlobalState>("/state_machine/global_state", nullptr);
        // drivemode_reader_ = node_->CreateReader<apollo::chassis::Chassis>("/pnc/chassis",  nullptr) ;
        DataHouse::Instance().CreateCache<apollo::chassis::Chassis>("/pnc/chassis");
        latency_reader_ = node_->CreateReader<apollo::patrol::ModuleLatency>(
            "/static/latency",
            [this](const std::shared_ptr<const apollo::patrol::ModuleLatency> &message) { get_latency(message); });
        perfinfo.set_obj_num(0);
        get_version();
        get_mounted_state();
        get_software_partnumber();
        get_dv_state();
        node_->CreateReader<apollo::dreamview::DVTestParams>(
            "/test/params", [this](const std::shared_ptr<const apollo::dreamview::DVTestParams> &msg) {
                this->on_dv_msg_coming(*msg);
        });
        node_->CreateReader<apollo::noa::NoaMsg>(
            "/hdmap/noa", [this](const std::shared_ptr<const apollo::noa::NoaMsg> &noamsg) {
                this->on_noamsg_coming(*noamsg);
        });
        using PerfMsgType = const std::shared_ptr<const perfanp::Perfmessage>;
        std::function<void(PerfMsgType)> perf_listener_callback =
            std::bind(&PerfComponent::on_perf_slave_msg, this, std::placeholders::_1);
        node_->CreateReader("/perf/perf_slave", perf_listener_callback);
    }

    auto profile = cybertron::middleware::QOS_PROFILE_DEFAULT;
    perf_writer_ = node_->CreateWriter<perfanp::Perfmessage>(conf.perf_channel(),    // channel名称
                                                             "perfanp.Perfmessage",  // channel所传输的数据格式
                                                             profile);               //
    ATRACE << "PerfComponent Init end.";

    for (auto &names : conf.module_name()) {
        module_latency[names.module_item()] = 0;
        module_drop_ratio[names.module_item()] = 0;
        module_message_latency[names.module_item()] = 0;
        module_cpu_time[names.module_item()] = 0;
    }

    return cybertron::SUCC;
}

bool PerfComponent::Proc() {
    if (!is_proc_init_) {
        std::lock_guard<std::mutex> lock(proc_init_mutex_);
        if (!is_proc_init_) {
            auto ret = ProcInit();
            if (ret != cybertron::SUCC) {
                AERROR << "PerfComponent init failed!";
                return false;
            }
            is_proc_init_ = true;
        }
    }

    if (enable_gpu_mem_monitor_) {
        print_gpu_info();
    }
    perfinfo.set_current_time_sec(apollo::cyber::Time::Now().ToSecond());
    if (conf.plate_type() == "master") {
        if (conf.topn_display()) {
            PERF_CPU << "[top_cpu]"
                     << "[perf]" << cpu_info;
        }
        if (conf.toph_display()) {
            PERF_CPU_H << "[top_cpu_thread]"
                     << "[perf_thread]" << cpu_info_thread;
        }
        get_drivemode();
        perfinfo.set_drive_mode(drivemode_);
        get_scene();
        perfinfo.set_drive_domain(scene_);
        perfinfo.set_executor_type(executor_type);
        PERF_CPU << "cur trafficlight: " << traffic_;
        perfinfo.set_trafficlight_scene(traffic_);

        PERF_CPU << "version: " << version_ << ", map_version: " << map_version_
            << ", task_purpose: " << task_purpose_ << ", test_path: " << task_path_
            << ", is_mounted: " << is_mounted_ << ", sp: " << software_partnumber_
            << ", dv: " << dv_state_ << ", lon: " << longtitude_ << ", lat: " << latitude_;
        apollo::common::util::LatencyRecord::Instance()->SetDriveMode(drivemode_);
        apollo::common::util::LatencyRecord::Instance()->SetDriveDomain(scene_);
        apollo::common::util::LatencyRecord::Instance()->SetFuncStateNum(funcstate_);
        apollo::common::util::LatencyRecord::Instance()->SetExecutorType(executor_type);

        if (mem_res_used != 0) {
            perfinfo.mutable_master_perf()->set_cpu(100 - id - wa);
        } else {
            perfinfo.mutable_master_perf()->set_cpu(0);
        }
        perfinfo.mutable_master_perf()->set_cpu_us(us);
        perfinfo.mutable_master_perf()->set_cpu_sy(sy);
        perfinfo.mutable_master_perf()->set_cpu_ni(ni);
        perfinfo.mutable_master_perf()->set_cpu_id(id);
        perfinfo.mutable_master_perf()->set_cpu_wa(wa);
        perfinfo.mutable_master_perf()->set_cpu_hi(hi);
        perfinfo.mutable_master_perf()->set_cpu_si(si);
        perfinfo.mutable_master_perf()->set_cpu_st(st);
        perfinfo.mutable_master_perf()->set_mem_res(mem_res_used / 1024);
        perfinfo.mutable_master_perf()->set_mem_total(mem_total / 1024);
        perfinfo.mutable_master_perf()->set_igpu_util(igpu_util_);
        perfinfo.mutable_master_perf()->set_iops(iops);
        perfinfo.mutable_master_perf()->set_non_sched_cpu(non_sched_cpu);
        perfinfo.mutable_master_perf()->set_is_remote_debug(is_remote_debug);
        perfinfo.mutable_master_perf()->set_cs(cs);
        perfinfo.mutable_master_perf()->set_pgfault(pgfault);
        perfinfo.mutable_master_perf()->set_cpu_temp(cpu_temp_);
        perfinfo.mutable_slave_perf()->set_cpu(cpu_slave_);
        perfinfo.mutable_slave_perf()->set_mem_res(mem_slave_);
        perfinfo.mutable_slave_perf()->set_mem_total(mem_total_slave_);
        if (anp_slave_cpu_ != 0.0f) {
            auto process_perf_slave = perfinfo.add_process_perf();
            process_perf_slave->set_process_name("mainboard -p compute2d_pnc_sched");
            process_perf_slave->set_process_cpu(anp_slave_cpu_);
        }

        for (auto const &net_temp : _res_net) {
            auto net_perf = perfinfo.mutable_master_perf()->add_netperf();
            net_perf->set_net_name(net_temp.first.c_str());
            net_perf->set_rxkb_value(_res_net[net_temp.first]["r_bytes"]);
            net_perf->set_txkb_value(_res_net[net_temp.first]["t_bytes"]);
            net_perf->set_rxpck_value(_res_net[net_temp.first]["r_packets"]);
            net_perf->set_txpck_value(_res_net[net_temp.first]["t_packets"]);
        }

        for (auto &names : conf.module_name()) {
            auto module_perf = perfinfo.add_module_latency_perf();
            module_perf->set_module_name(names.module_item());
            module_perf->set_module_latency(module_latency[names.module_item()]);
            module_perf->set_module_drop_ratio(module_drop_ratio[names.module_item()]);
            if (names.module_item() != "Endlatency") {
                module_perf->set_module_message_latency(module_message_latency[names.module_item()]);
            }
            module_perf->set_module_cpu_time(module_cpu_time[names.module_item()]);
        }

        if (anp_master != 0.0f) {
            auto process_perf = perfinfo.add_process_perf();
            process_perf->set_process_name("mainboard -p compute2d_sched");
            process_perf->set_process_cpu(anp_master);
        }
    } else if (conf.plate_type() == "slave") {
        if (conf.topn_display()) {
            PERF_CPU_SLAVE << "[top_cpu]"
                           << "[perf]" << cpu_info;
        }

        if (conf.toph_display()) {
            PERF_CPU_SLAVE_H << "[top_cpu_thread]"
                     << "[perf_thread]" << cpu_info_thread;
        }
        if (mem_res_used != 0) {
            perfinfo.mutable_slave_perf()->set_cpu(100 - id - wa);
        } else {
            perfinfo.mutable_slave_perf()->set_cpu(0);
        }
        perfinfo.mutable_slave_perf()->set_cpu_us(us);
        perfinfo.mutable_slave_perf()->set_cpu_sy(sy);
        perfinfo.mutable_slave_perf()->set_cpu_ni(ni);
        perfinfo.mutable_slave_perf()->set_cpu_id(id);
        perfinfo.mutable_slave_perf()->set_cpu_wa(wa);
        perfinfo.mutable_slave_perf()->set_cpu_hi(hi);
        perfinfo.mutable_slave_perf()->set_cpu_si(si);
        perfinfo.mutable_slave_perf()->set_cpu_st(st);
        perfinfo.mutable_slave_perf()->set_mem_res(mem_res_used / 1024);
        perfinfo.mutable_slave_perf()->set_mem_total(mem_total / 1024);
        perfinfo.mutable_slave_perf()->set_igpu_util(igpu_util_);
        perfinfo.mutable_slave_perf()->set_iops(iops);
        perfinfo.mutable_slave_perf()->set_non_sched_cpu(non_sched_cpu);
        perfinfo.mutable_slave_perf()->set_is_remote_debug(is_remote_debug);
        perfinfo.mutable_slave_perf()->set_cs(cs);
        perfinfo.mutable_slave_perf()->set_pgfault(pgfault);
        perfinfo.mutable_slave_perf()->set_cpu_temp(cpu_temp_);

        for (auto const &net_temp : _res_net) {
            auto net_perf = perfinfo.mutable_slave_perf()->add_netperf();
            net_perf->set_net_name(net_temp.first.c_str());
            net_perf->set_rxkb_value(_res_net[net_temp.first]["r_bytes"]);
            net_perf->set_txkb_value(_res_net[net_temp.first]["t_bytes"]);
            net_perf->set_rxpck_value(_res_net[net_temp.first]["r_packets"]);
            net_perf->set_txpck_value(_res_net[net_temp.first]["t_packets"]);
        }

        if (anp_slave != 0.0f) {
            auto process_perf = perfinfo.add_process_perf();
            process_perf->set_process_name("mainboard -p compute2d_pnc_sched");
            process_perf->set_process_cpu(anp_slave);
        }
    }

    perf_writer_->Write(std::make_shared<perfanp::Perfmessage>(perfinfo));
    perfinfo.clear_module_latency_perf();
    perfinfo.mutable_master_perf()->clear_netperf();
    perfinfo.mutable_slave_perf()->clear_netperf();
    perfinfo.clear_process_perf();

    static uint64_t epoch = 1;
    static size_t u64sz = sizeof(uint64_t);
    static size_t allocated{0};
    static size_t active{0};
    static size_t metadata{0};
    static size_t resident{0};
    static size_t mapped{0};
    static size_t size_t_size = sizeof(size_t);
    allocated = 0;
    active = 0;
    metadata = 0;
    resident = 0;
    mapped = 0;
    mallctl("epoch", &epoch, &u64sz, &epoch, u64sz);
    mallctl("stats.allocated", reinterpret_cast<void*>(&allocated), &size_t_size, NULL, 0);
    mallctl("stats.active", reinterpret_cast<void*>(&active), &size_t_size, NULL, 0);
    mallctl("stats.metadata", reinterpret_cast<void*>(&metadata), &size_t_size, NULL, 0);
    mallctl("stats.resident", reinterpret_cast<void*>(&resident), &size_t_size, NULL, 0);
    mallctl("stats.mapped", reinterpret_cast<void*>(&mapped), &size_t_size, NULL, 0);

    int32_t free_slot = get_asan_status();
    int32_t free_slot1 = get_asan_status1();
    if (conf.plate_type() == "master") {
        PERF_CPU << "stats allocated: " << allocated << " active: " << active << " metadata: " << metadata
                 << " resident: " << resident << " mapped: " << mapped;
        if(free_slot != -1 || free_slot1 != -1) {
            PERF_CPU << "gwp_asan free slot: " << free_slot << " " << free_slot1;
        }
    } else {
        PERF_CPU_SLAVE << "stats allocated: " << allocated << " active: " << active << " metadata: " << metadata
                 << " resident: " << resident << " mapped: " << mapped;
        if(free_slot != -1 || free_slot1 != -1) {
            PERF_CPU_SLAVE << "gwp_asan free slot: " << free_slot << " " << free_slot1;
        }
    }

    return cybertron::SUCC;
}

void PerfComponent::on_dv_msg_coming(const apollo::dreamview::DVTestParams &msg) {
    if (task_purpose_.empty()) {
        std::lock_guard<std::mutex> lk(info_mutex_);
        if (task_purpose_.empty()) {
            if (msg.has_test_op() && msg.test_op() == apollo::dreamview::DVTestParams::QA) {
                task_purpose_ = "roadtest";
            } else if (msg.has_test_op() && msg.test_op() == apollo::dreamview::DVTestParams::RD) {
                task_purpose_ = "debug";
            }
        }
    }
    if (msg.has_test_path()) {
        std::string path = msg.test_path();
        if (!path.empty()) {
            std::lock_guard<std::mutex> lk(info_mutex_);
            task_path_ = path;
        }
    }
    if (msg.has_longtitude()) {
        double longtitude = msg.longtitude();
        std::lock_guard<std::mutex> lk(info_mutex_);
        longtitude_ = longtitude;
    }
    if (msg.has_latitude()) {
        double latitude = msg.latitude();
        std::lock_guard<std::mutex> lk(info_mutex_);
        latitude_ = latitude;
    } 
}

void PerfComponent::on_noamsg_coming(const apollo::noa::NoaMsg &noamsg) {
    if (!map_version_.empty()) {
        return;
    }
    std::lock_guard<std::mutex> lk(info_mutex_);
    if (map_version_.empty()) {
        std::string map_version = noamsg.map_version();
        if (!map_version.empty()) {
            auto split_pos = map_version.find("|");
            if (split_pos != std::string::npos) {
                map_version_ = map_version.substr(0, split_pos);
            }
        }
    }
}

void PerfComponent::on_perf_slave_msg(const std::shared_ptr<const perfanp::Perfmessage> &message) {
    if (message == nullptr) {
        return;
    }
    if (message->has_slave_perf()) {
        cpu_slave_ = message->slave_perf().cpu();
        mem_slave_ = message->slave_perf().mem_res();
        mem_total_slave_ = message->slave_perf().mem_total();
    }
    anp_slave_cpu_ = 0.0f;
    for (const auto& process_perf : message->process_perf()) {
        if (process_perf.process_name() == "mainboard -p compute2d_pnc_sched") {
            anp_slave_cpu_ = process_perf.process_cpu();
        }
    }
}

void PerfComponent::get_version() {
    char* path = getenv("CYBERTRON_PATH");
    if (path == nullptr) {
        return;
    }

    std::string release_notes = std::string(path)+ "/release_notes";
    std::ifstream fs(release_notes);
    std::string line;
    getline(fs, line);
    std::string iso_version;
    if (line.find(":") != std::string::npos) {
        auto pos = line.find(":");
        iso_version = line.substr(pos + 1);
    }
    fs.close();
    version_ = Trim(iso_version);
}

void PerfComponent::get_mounted_state() {
    std::string cmd = "df -h | grep /media/caros/nvme1 | wc -l";
    std::string result = "";
    FILE* fp = popen(cmd.c_str(), "r");
    char buffer[128] = {0};
    while (fp != nullptr && fgets(buffer, sizeof(buffer), fp)) {
        result += std::string(buffer);
        if (!result.empty() && result.back() == '\n') {
     	   result.pop_back();
    	}
	    break;
    }
    is_mounted_ = result;
    pclose(fp);
}

void PerfComponent::get_software_partnumber() {
    std::string cmd = "cat /opt/integration-version.txt | grep software_partnumber";
    std::string result = "";
    FILE* fp = popen(cmd.c_str(), "r");
    char buffer[128] = {0};
    while (fp != nullptr && fgets(buffer, sizeof(buffer), fp)) {
        result += std::string(buffer);
    }
    pclose(fp);
    // 使用istringstream来分割字符串
    std::istringstream iss(result);
    std::string word;
    int column = 0;
    while (iss >> word) {
        column++;
        if (column >= 2) {
            software_partnumber_ += word;
        }
    }
}

void PerfComponent::get_dv_compress() {
    std::string cmd = "cat /opt/anp/conf/dreamview/dreamview.flag | grep enable_upload_data";
    std::string result = "";
    FILE* fp = popen(cmd.c_str(), "r");
    char buffer[128] = {0};
    while (fp != nullptr && fgets(buffer, sizeof(buffer), fp)) {
        result += std::string(buffer);
        if (!result.empty() && result.back() == '\n') {
     	   result.pop_back();
    	}
        break;
    }
    pclose(fp);
    std::size_t pos = result.find("=");
    if (pos != std::string::npos) {
        std::string value = result.substr(pos + 1);
        if (value == "false") {
            dv_state_ = "2";
        }
    }
}

void PerfComponent::get_dv_state() {
    std::string cmd = "cat /opt/anp/launch/orin_navigation_master.launch | grep dreamview.dag";
    FILE* fp = popen(cmd.c_str(), "r");
    char buffer[128] = {0};
    dv_state_ = "0";
    while (fp != nullptr && fgets(buffer, sizeof(buffer), fp)) {
        if (std::string(buffer).find("<dag_conf>dreamview.dag</dag_conf>") != std::string::npos) {
            dv_state_ = "1";
            std::cout << "open" << std::endl;
            get_dv_compress();
            break;
        }
    }
    pclose(fp);
}

void PerfComponent::get_process_cpu(const std::string& buffer, float& process_cpu) {
    std::istringstream iss(buffer);
    std::string token;
    int column = 0;
    while (iss >> token) {
        column++;
        if (column == 9) { // %CPU列位于第9列
            process_cpu = atof(token.c_str());
            break;
        }
    }
}

int PerfComponent::cpu_check_thread() {
    cpu_thread = std::make_shared<std::thread>([&]() {
        std::string cmd = "top -c -w 500 -d 1 -b";
        fp_cpu = popen(cmd.c_str(), "r");
        if (conf.pidstat_display()){
            std::string cmd_pidstat = "pidstat -t 1 -d";
            fp_pidstat_ = popen(cmd_pidstat.c_str(), "r");
        }
        if (conf.toph_display()){
            std::string cmd_top_h = "top -H -w 500 -d 1 -b | grep \"^top - \" -A 55";
            fp_cpu_thread = popen(cmd_top_h.c_str(), "r");
        }

        while (1) {
            if (killed) {
                PERF_CPU << "killed";
                break;
            }
            double start_test_time = apollo::cyber::Time::Now().ToSecond();
            bool top_print = true;
            bool begin_flag = false;
            bool begin_toph_flag = false;
            bool begin_pidstat_flag = false;
            char buffer[1024] = {0};
            char thread_buffer[32] = {0};
            cpu_info = "\n";
            cpu_info_thread = "\n";
            int temp_non_sched_cpu = 0;
            is_remote_debug = false;
            anp_master = 0.0f;
            anp_slave = 0.0f;
            while (fp_cpu != nullptr && fgets(buffer, sizeof(buffer), fp_cpu)) {
                if (top_print) {
                    cpu_info += std::string(buffer);
                    if (std::string(buffer).find("Cpu(s):") != std::string::npos) {
                        us = atof(Trim(std::string(buffer).substr(8, 5)).c_str());
                        sy = atof(Trim(std::string(buffer).substr(17, 5)).c_str());
                        ni = atof(Trim(std::string(buffer).substr(26, 5)).c_str());
                        id = atof(Trim(std::string(buffer).substr(35, 5)).c_str());
                        wa = atof(Trim(std::string(buffer).substr(44, 5)).c_str());
                        hi = atof(Trim(std::string(buffer).substr(53, 5)).c_str());
                        si = atof(Trim(std::string(buffer).substr(62, 5)).c_str());
                        st = atof(Trim(std::string(buffer).substr(71, 5)).c_str());
                    } else if (std::string(buffer).find("KiB Mem :") != std::string::npos) {
                        mem_total = atof(Trim(std::string(buffer).substr(9, 9)).c_str());
                        mem_res_used = atof(Trim(std::string(buffer).substr(40, 9)).c_str());
                    } else if (std::string(buffer).find("MiB Mem :") != std::string::npos) {
                        mem_total = atof(Trim(std::string(buffer).substr(9, 9)).c_str()) * 1024;
                        mem_res_used = atof(Trim(std::string(buffer).substr(40, 9)).c_str()) * 1024;
                    } else if (std::string(buffer).find("mainboard -p compute2d_sched") != std::string::npos) {
                        get_process_cpu(buffer, anp_master);
                    } else if (std::string(buffer).find("mainboard -p compute2d_pnc_sched") != std::string::npos) {
                        get_process_cpu(buffer, anp_slave);
                    }
                }
                if (std::string(buffer).find("\%CPU") != std::string::npos) {
                    begin_flag = true;
                    continue;
                }
                if (!begin_flag) {
                    continue;
                }
                if (std::string(buffer) == "\n") {
                    break;
                }
                if (std::string(buffer).length() > 52 && top_print) {
                    float cpu = 0.0;
                    float mem_proportion = 0.0;
                    uint32_t process_id;
                    sscanf(buffer, "%u %*s %*s %*s %*s %*s %*s %*s %f %f", &process_id, &cpu, &mem_proportion);
                    uint32_t mem_res = mem_total * mem_proportion / 100 / 1024;
                    temp_non_sched_cpu += cpu;
                    if (cpu <= 0.0) {
                        top_print = false;
                    }
                }
            }
            cpu_info += "\n";
            // top -h
            if (conf.toph_display()){
                begin_toph_flag = false;
                while (fp_cpu_thread != nullptr && fgets(buffer, sizeof(buffer), fp_cpu_thread)) {
                    cpu_info_thread += std::string(buffer);
                    if (std::string(buffer).find("\%CPU") != std::string::npos) {
                        begin_toph_flag = true;
                        continue;
                    }
                    if (!begin_toph_flag) {
                        continue;
                    }
                    if (std::string(buffer).find ("--") != std::string::npos) {
                        break;
                    }
                }
                cpu_info_thread += "\n";
            }
            

            // pidstat -d 
            if (conf.pidstat_display()){
                begin_pidstat_flag = false;
                    while (fp_pidstat_ != nullptr && fgets(buffer, sizeof(buffer), fp_pidstat_)) {
                        cpu_info_thread += std::string(buffer);
                        if(std::string(buffer).find("kB_rd/s") != std::string::npos) {
                            begin_pidstat_flag = true;
                            continue;
                        }
                        if(!begin_pidstat_flag){
                            continue;
                        }
                        if (std::string(buffer) == "\n") {
                            break;
                        }
                }
                cpu_info_thread += "\n";
            }

            cpu_info += "\n";

            double end_test_time = apollo::cyber::Time::Now().ToSecond();
            if (conf.plate_type() == "master") {
                PERF_CPU << "cpu get data cost time(s): " << end_test_time - start_test_time <<
                    ",igpu_util: " << igpu_util_ << ",non_sched_cpu: " <<  temp_non_sched_cpu <<
                    ",iops: " << iops << ",is_remote_debug: " << is_remote_debug;
            }
            if (conf.plate_type() == "slave") {
                PERF_CPU_SLAVE << "cpu get data cost time(s): " << end_test_time - start_test_time <<
                    ",igpu_util: " << igpu_util_ << ",non_sched_cpu: " <<  temp_non_sched_cpu <<
                    ",iops: " << iops << ",is_remote_debug: " << is_remote_debug;
            }
            // int sleep_utime =(end_test_stime - start_test_time)<1?int((1 - (end_test_time - start_test_time))*1e6):0;
            // usleep(sleep_utime);
            non_sched_cpu = temp_non_sched_cpu;
            if ((end_test_time - start_test_time) < 1) {
                apollo::time::Rate(1.0).sleep();
            }
        }
    });
    apollo::cyber::scheduler::Instance()->SetInnerThreadAttr(cpu_thread.get(), "perfanp_cpu");
    return cybertron::SUCC;
}

int PerfComponent::io_check_thread() {
    io_thread = std::make_shared<std::thread>([&]() {
        std::string cmd = "iostat -t 1";
        fp_io = popen(cmd.c_str(), "r");
        char buffer[1024] = {0};
        char ifname[100] = {0};
        int r_bytes = 0, t_bytes = 0, r_packets = 0, t_packets = 0;
        char net_result[1024] = {0};
        std::unordered_map<std::string, std::unordered_map<std::string, int>> cur_net;
        std::unordered_map<std::string, std::unordered_map<std::string, int>> last_net;
        bool net_begin = true;
        int last_cs = 0;
        int cur_cs = 0;
        int last_pgfault = 0;
        int cur_pgfault = 0;
        while (1) {
            if (killed) {
                PERF_CPU << "killed";
                break;
            }
            double start_test_time = apollo::cyber::Time::Now().ToSecond();
            while (fp_io != nullptr && fgets(buffer, sizeof(buffer), fp_io)) {
                if (std::string(buffer).find(conf.mutable_ioperf()->io_item()) != std::string::npos ||
                    std::string(buffer).find("sdb") != std::string::npos) {
                    iops = atof(Trim(std::string(buffer).substr(14, 5)).c_str());
                }
                if (std::string(buffer) == "\n") {
                    break;
                }
            }

            fp_net = fopen("/proc/net/dev", "r");
            int i = 0;
            while (fp_net != nullptr && fgets(buffer, sizeof(buffer), fp_net)) {
                i++;
                if (i < 3) {
                    continue;  // skip first two lines
                }
                sscanf(buffer, " %99[^:]: %d %d %*d %*d %*d %*d %*d %*d %d %d", ifname, &r_bytes, &r_packets, &t_bytes,
                       &t_packets);
                if (net_begin) {
                    net_begin = false;
                    last_net[ifname]["r_bytes"] = r_bytes;
                    last_net[ifname]["t_bytes"] = t_bytes;
                    last_net[ifname]["r_packets"] = r_packets;
                    last_net[ifname]["t_packets"] = t_packets;
                } else {
                    last_net[ifname]["r_bytes"] = cur_net[ifname]["r_bytes"];
                    last_net[ifname]["t_bytes"] = cur_net[ifname]["t_bytes"];
                    last_net[ifname]["r_packets"] = cur_net[ifname]["r_packets"];
                    last_net[ifname]["t_packets"] = cur_net[ifname]["t_packets"];
                }
                cur_net[ifname]["r_bytes"] = r_bytes;
                cur_net[ifname]["t_bytes"] = t_bytes;
                cur_net[ifname]["r_packets"] = r_packets;
                cur_net[ifname]["t_packets"] = t_packets;
                _res_net[ifname]["r_bytes"] =
                    static_cast<float>((cur_net[ifname]["r_bytes"] - last_net[ifname]["r_bytes"]) / 1024.0);
                _res_net[ifname]["t_bytes"] =
                    static_cast<float>((cur_net[ifname]["t_bytes"] - last_net[ifname]["t_bytes"]) / 1024.0);
                _res_net[ifname]["r_packets"] =
                    static_cast<float>(cur_net[ifname]["r_packets"] - last_net[ifname]["r_packets"]);
                _res_net[ifname]["t_packets"] =
                    static_cast<float>(cur_net[ifname]["t_packets"] - last_net[ifname]["t_packets"]);
            }
            if (fp_net != nullptr) {
                fclose(fp_net);
            }

            cur_cs = get_sys_metrics("/proc/stat", "ctxt");
            cur_pgfault = get_sys_metrics("/proc/vmstat", "pgfault");
            cs = cur_cs - last_cs;
            pgfault = cur_pgfault - last_pgfault;
            last_cs = cur_cs;
            last_pgfault = cur_pgfault;
            std::string cpu_temp = "/sys/devices/virtual/thermal/thermal_zone0/temp";
            cpu_temp_ = get_cpu_temp(cpu_temp.c_str());

            double end_test_time = apollo::cyber::Time::Now().ToSecond();
            if (conf.plate_type() == "master") {
                for (auto const &net_temp : _res_net) {
                    snprintf(net_result, sizeof(net_result),
                             "%s: rxkB/s: %.2f txkB/s: %.2f rxpck/s: %.2f txpck/s: %.2f \n", net_temp.first.c_str(),
                             _res_net[net_temp.first]["r_bytes"], _res_net[net_temp.first]["t_bytes"],
                             _res_net[net_temp.first]["r_packets"], _res_net[net_temp.first]["t_packets"]);
                    PERF_CPU << net_result;
                }
                PERF_CPU << "system cs: " << cs;
                PERF_CPU << "system pgfault: " << pgfault;
                PERF_CPU << "iostat get data cost time(s): " << end_test_time - start_test_time;
                PERF_CPU << "cpu temp: " << cpu_temp_;
            }
            if (conf.plate_type() == "slave") {
                for (auto const &net_temp : _res_net) {
                    snprintf(net_result, sizeof(net_result),
                             "%s: rxkB/s: %.2f txkB/s: %.2f rxpck/s: %.2f txpck/s: %.2f \n", net_temp.first.c_str(),
                             _res_net[net_temp.first]["r_bytes"], _res_net[net_temp.first]["t_bytes"],
                             _res_net[net_temp.first]["r_packets"], _res_net[net_temp.first]["t_packets"]);
                    PERF_CPU_SLAVE << net_result;
                }
                PERF_CPU_SLAVE << "system cs: " << cs;
                PERF_CPU_SLAVE << "system pgfault: " << pgfault;
                PERF_CPU_SLAVE << "iostat get data cost time(s): " << end_test_time - start_test_time;
                PERF_CPU_SLAVE << "cpu temp: " << cpu_temp_;
            }
            // int sleep_utime =(end_test_time - start_test_time)<1?int((1 - (end_test_time - start_test_time))*1e6):0;
            // usleep(sleep_utime);
            CheckNotResponse();
            apollo::time::Rate(1.0).sleep();
        }
    });
    apollo::cyber::scheduler::Instance()->SetInnerThreadAttr(io_thread.get(), "perfanp_io");
    return cybertron::SUCC;
}

void PerfComponent::CheckNotResponse() {
    if (!is_orinx_ || !enable_dump_all_bt_) {
        return;
    }
    if (apollo::cyber::IsShutdown() || conf.plate_type() == "master") {
        return;
    }

    apollo::common::util::OrinxPlate plate = apollo::common::util::OrinxPlate::SLAVE;
    if (apollo::common::util::LatencyRecord::Instance()->IsDumpAllThreadBacktrace(plate)) {
        std::string bt;
        std::cout<< "start get all bt" << std::endl;
        apollo::logger::DumpThreadBacktrace(&bt);
        std::cout<< "start print all bt" << std::endl;
        std::cout << bt << std::endl;
        std::cout<< "stop print all bt" << std::endl;
        ApplicationNotResponse();
    }
}

void PerfComponent::ApplicationNotResponse() {
    std::raise(SIGABRT);
}

std::string PerfComponent::Trim(std::string str) {
    str.erase(0, str.find_first_not_of(" "));
    str.erase(str.find_last_not_of(" ") + 1);
    return str;
}

void PerfComponent::get_scene() {
    scene_reader_->CyberReader()->Observe();
    const auto message = scene_reader_->CyberReader()->GetLatestObserved();
    if (message == nullptr) {
        return;
    }
    executor_type = message->executor_type();

    statemachine_reader_->CyberReader()->Observe();
    const auto &statemachine_message = statemachine_reader_->CyberReader()->GetLatestObserved();
    if (statemachine_message == nullptr) {
        return;
    }
    if (statemachine_message->domain_state() == 0) {
        scene_ = perfanp::Drivedomain::HIGHWAY;
    } else if (statemachine_message->domain_state() == 1) {
        scene_ = perfanp::Drivedomain::URBAN;
    } else if (statemachine_message->domain_state() == 2) {
        scene_ = perfanp::Drivedomain::MIX_AREA;
    }

    funcstate_ = statemachine_message->function_state() + 1;

    PERF_CPU << "cur drivedomain: " << scene_;
    PERF_CPU << "cur funcstate: " << funcstate_;
}

void PerfComponent::get_drivemode() {
    // drivemode_reader_->CyberReader()->Observe();
    // const auto &message = drivemode_reader_->CyberReader()->GetLatestObserved();
    const auto message = DataHouse::Instance().GetLatest<apollo::chassis::Chassis>();
    if (message == nullptr) {
        return;
    }
    if (message->driving_mode() == 1) {
        drivemode_ = perfanp::Drivemode::AUTO;
    } else {
        drivemode_ = perfanp::Drivemode::MANU;
    }
    PERF_CPU << "cur drivemode: " << drivemode_;
}

void PerfComponent::get_latency(const std::shared_ptr<const apollo::patrol::ModuleLatency> &message) {
    if (message == nullptr) {
        return;
    }
    for (auto &names : message->module_latency()) {
        module_latency[names.module_name()] = names.value() / 1e6;
        module_drop_ratio[names.module_name()] = names.drop_ratio();
        if (names.module_name() != "Endlatency") {
            module_message_latency[names.module_name()] = names.message_value() / 1e6;
        }
        module_cpu_time[names.module_name()] = names.module_cpu_time() / 1e6;
    }
}

int PerfComponent::get_sys_metrics(const char *filename, std::string s) {
    char buffer[1024] = {0};
    char ifname[100] = {0};
    int metric = 0;
    fp_metric = fopen(filename, "r");
    while (fp_metric != nullptr && fgets(buffer, sizeof(buffer), fp_metric)) {
        if (std::string(buffer).find(s) != std::string::npos) {
            sscanf(buffer, "%99s %d", ifname, &metric);
            break;
        }
    }
    if (fp_metric != nullptr) {
        fclose(fp_metric);
    }
    return metric;
}

int PerfComponent::get_cpu_temp(const char *filename) {
    char buffer[1024] = {0};
    int temp = 0;
    fp_temp = fopen(filename, "r");
    while (fp_temp != nullptr && fgets(buffer, sizeof(buffer), fp_temp)) {
        sscanf(buffer, "%d", &temp);
    }
    if (fp_temp != nullptr) {
        fclose(fp_temp);
    }
    return temp;
}

std::vector<std::string> PerfComponent::split_by_space(const std::string& str) {
    std::vector<std::string> res;
    int j = 0;
    for (int i = 0; i < str.length(); i++) {
        if (str[i] == ' ') {
            if (i - j > 0) {
                res.emplace_back(str.substr(j, i - j));
            }
            j = i + 1;
        }
    }
    if (j != res.size()) {
      res.emplace_back(str.substr(j, str.size() - j));
    }
    return res;
}

void PerfComponent::print_gpu_info() {
    std::string file_name = "/sys/kernel/debug/nvmap/iovmm/clients";
    FILE* fd = fopen(file_name.c_str(), "r");
    if (fd == nullptr) {
        return;
    }
    std::stringstream ss;
    char buff[1024] = {0};
    while (true) {
        if (fgets(buff, sizeof(buff), fd) == nullptr) {
            break;
        }
        std::string line(buff);
        if (line.size() < 1) {
            continue;
        }
        auto pos1 = line.find("user");
        if (pos1 != std::string::npos) {
            if (line[line.size() - 1] == '\n') {
                line.pop_back();
            }
            auto res = split_by_space(line);
            if (res.size() != 4) {
                continue;
            }
            ss<< res[1] << "," << res[2] << "," << res[3] << ";";
        }
        pos1 = line.find("total");
        if (pos1 != std::string::npos) {
            if (line[line.size() - 1] == '\n') {
                line.pop_back();
            }
            auto res = split_by_space(line);
            if (res.size() != 2) {
                continue;
            }
            ss << res[0] << "," << res[1] << ";";
        }
    }
    fclose(fd);

    if (ss.str().size() > 0) {
        if (conf.plate_type() == "master") {
            PERF_CPU << "gpu_info: " <<  ss.str();
        } else {
            PERF_CPU_SLAVE << "gpu_info: " <<  ss.str();
        }
    }
}

}  // namespace perfcom
